#ifndef CALCULATOR_H
#define CALCULATOR_H

#include <iostream>
#include <vector>
#include <stdio.h>
#include <math.h>
#include <string.h>

using namespace std;

class calculator
{
private:
  string _exp; //原始表达式
  vector<double> nums; //从原始表达式拆分而来的存储数字的数组
  vector<char> ops; //从原始表达式拆分而来的存储运算符的数组
  vector<int> ops_level; //运算符数组的转译，对应运算符的优先级
  
  struct post_exp_unit //后缀表达式的一个单元
  {
    bool type; //类型为1说明是数字，为0说明是运算符
    double num;
    char op;
  public:
    post_exp_unit(){}
    post_exp_unit(bool _type,double _num,char _op)
    {
      this->type = _type;
      this->num = _num;
      this->op = _op;
    }
  };
  
  vector<post_exp_unit*> post_exp; //存储后缀表达式的数组

public:
  bool op_judge(char ch) //判断一个输入字符是否合法
  {
    if(ch == '+' || ch == '-' || ch == '*' || ch == '/'
       || ch == '(' || ch == ')' || ch == '^')
      return true;
    
    else return false;
  }
  
  int exp_input(bool mode) //读取一个表达式并完成合理性判断以及拆分工作
  {
    getline(cin,_exp);
    if(mode) cout << _exp << endl; //只有这里用到了mode，主要是规范example.cpp的输出
    int integer_judge = 1,decimal_count = 0; //前一个变量决定以整数还是小数输入，后一个变量记录小数输入到第几位了
    
    if((_exp[0] < '0' || _exp[0] > '9') && (_exp[0] != '(' && _exp[0] != '-'))
      return 6; //检测第一个字符是否符合要求，否则说明表达式有误
    else if(_exp[0] == '.')
      return 4; //表达式上来就是小数点那肯定是错的
    
    for(int i = 0; _exp[i]!='\0'; i++)
      {
	if(_exp[i] >= '0' && _exp[i] <= '9' || _exp[i] == '.') //判断是否加入一个新的数字以及是否存在小数点
	  {
	    if(i == 0)
	      nums.push_back(0);
	    else if((_exp[i-1] < '0' || _exp[i-1] > '9') && _exp[i-1] != '.') 
	      nums.push_back(0);
	  else if(_exp[i] == '.')
	    {
	      if(_exp[i+1] < '0' || _exp[i+1] > '9')
	        return 4; 
	      integer_judge = 0;
	      continue;
	    }
	    
	    if(integer_judge) //由char向double的转变
	      nums[nums.size()-1] = nums[nums.size()-1] * 10 + (_exp[i] - '0');
	    else
	      nums[nums.size()-1] = nums[nums.size()-1] + pow(10,--decimal_count)*(_exp[i] - '0');
	  }
	
	else if(op_judge(_exp[i]))
	  {
	    integer_judge = 1; //重置这俩变量等到下一次输入数字再用
	    decimal_count = 0;
	    
	    if(i == 0 && _exp[i] == '-')
	      nums.push_back(0);
	    
	    if(_exp[i] == '(' && _exp[i+1] == '-')
	      nums.push_back(0); //将负号变为双目运算
	    
	    if(i+1 < _exp.size() && (_exp[i] == ')' && _exp[i+1] == '(' && op_judge(_exp[i+1])))
	      return 2;
	    else if(_exp[i] == ')')
	      ops.push_back(_exp[i]);
	    else if(i+1 < _exp.size() && _exp[i] == '(' && _exp[i+1] == '-')
	      ops.push_back(_exp[i]);
	    else if(i+1 < _exp.size() && (_exp[i] == '(' && _exp[i+1] == ')' && op_judge(_exp[i+1])))
	      return 7;
	    else if(i+1 < _exp.size() && (_exp[i+1] != '(' && _exp[i+1] != ')' && op_judge(_exp[i+1])))
	      return 1;
	    else if(i == _exp.size()-1 && _exp[i] != ')')
	      return 1;
	    else
	      ops.push_back(_exp[i]); //运算符合理性判断，详情请见report
	  }
	
	else
	 return 6;
      }
    
    int blanket_count = 0; //进行括号匹配检查
    for(int i = 0; i < ops.size() ; i++)
      {
	if(ops[i] == '(') blanket_count++; //检测到前括号就加1，检测到后括号就减1
	else if(ops[i] == ')') blanket_count--;
	
	if(blanket_count < 0) return 3;  //一旦统计出负的就说明有个后括号没有前括号，直接报错
      }
    if(blanket_count != 0) return 3; //前面跑完还是正的就说明有个前括号没有后括号，报错
    
    return 0;
  }
  
  void level()  //为运算符赋权，具体解释详见report
  {
    for(int i = 0; i < ops.size() ; i++)
      {
	if(ops[i] == ')')
	  ops_level.push_back(0);
	else if(ops[i] == '+' || ops[i] == '-')
	  ops_level.push_back(1);
	else if(ops[i] == '*' || ops[i] == '/')
	  ops_level.push_back(2);
	else if(ops[i] == '^')
	  ops_level.push_back(3);
	else if(ops[i] == '(')
	  ops_level.push_back(4);
      }
  }
  
  vector<int> place = {0}; //这个数组和下面那个函数起到迭代器的作用（应该可以这么说吧），具体运作见report
  
  int pl()
  {
    int sum = 0;
    for(int i = 0; i < place.size() ; i++)
      sum += place[i];
    return place.size()-1 + sum;
  }
  
  void post_exp_ops() //考虑到后续要写很多重复的下列代码，单拎出来作为函数
  {
    post_exp_unit* unit = new post_exp_unit(0,0,ops[pl()]);
    post_exp.push_back(unit);
    ops.erase(ops.begin() + pl());
    ops_level.erase(ops_level.begin() + pl());
  }
  
  int post() //中缀转后缀
  {
    post_exp_unit* unit = new post_exp_unit(1,nums[0],'0'); //一个表达式的数字一定比运算符多一个，根据程序逻辑首先把第一个数字推到后缀表达式里面去
    post_exp.push_back(unit);
    nums.erase(nums.begin());
    
    while(ops.size()) //这一段详见report
      {
	if(ops_level[pl()] >= 1 && ops_level[pl()] <= 3)
	  {
	    post_exp_unit* unit = new post_exp_unit(1,nums[0],'0');
	    post_exp.push_back(unit);
	    nums.erase(nums.begin());
	  }
	else if(ops_level[pl()] == 0)
	  {
	    for(int k = 1; k <= 2 ; k++) 
	      {
		ops.erase(ops.begin() + pl()-1);
		ops_level.erase(ops_level.begin() + pl()-1);
	      }
	    place.pop_back();
	    if(place[place.size()-1] > 0)
	      {
		place[place.size()-1]--;
	      }
	    else
	      continue;
	  }
	if(ops_level[pl()] == 4)
	  {
	    place.push_back(0);
	    continue;
	  }
	
	
	if(pl() < ops_level.size()-1) //这一段也是
	  {
	    if(ops_level[pl()] < ops_level[pl()+1] || (ops_level[pl()] == ops_level[pl()+1] && ops_level[pl()] == 3))
	      {
		place[place.size()-1]++;
		continue;
	      }
	    else
	      {
		while(ops_level[pl()] >= ops_level[pl()+1]
		      && place[place.size()-1] > 0)
		  {
		    post_exp_ops();
		    place[place.size()-1]--;
		  }
		if(ops_level[pl()] < ops_level[pl()+1])
		  place[place.size()-1]++;
		else if(place[place.size()-1] == 0)
		  post_exp_ops();
	      }
	  }
	else
	  {
	    if(pl() > ops_level.size()-1)
	      place[place.size()-1]--;
	    while(place[place.size()-1] >= 0)
	      {
		post_exp_ops();
		place[place.size()-1]--;
	      }
	  }
      }
    
    if(nums.size() != 0) return 2; //上面跑完如果数字数组里还剩数字则说明这个表达式缺运算符
    return 0;
  }
  
  vector<double> cal; //“草纸”，当它是个栈
  
  int _calculate() //得到后缀表达式之后这就是一个非常常规的栈操作
  {
    for(int i = 0; i < post_exp.size() ; i++)
      {
	if(post_exp[i]->type)
	  {
	    cal.push_back(post_exp[i]->num);
	  }
	else
	  {
	    if(post_exp[i]->op == '+')
	      {
		cal[cal.size()-2] = cal[cal.size()-2] + cal[cal.size()-1];
		cal.pop_back();
	      }
	    else if(post_exp[i]->op == '-')
	      {
		cal[cal.size()-2] = cal[cal.size()-2] - cal[cal.size()-1];
		cal.pop_back();
	      }
	    else if(post_exp[i]->op == '*')
	      {
		cal[cal.size()-2] = cal[cal.size()-2] * cal[cal.size()-1];
		cal.pop_back();
	      }
	    else if(post_exp[i]->op == '/')
	      {
		if(cal[cal.size()-1] == 0)return 5;
		cal[cal.size()-2] = cal[cal.size()-2] / cal[cal.size()-1];
		cal.pop_back();
	      }
	    else if(post_exp[i]->op == '^')
	      {
		cal[cal.size()-2] = pow(cal[cal.size()-2],cal[cal.size()-1]);
		cal.pop_back();
	      }
	  }
      }
    return 0;
  }

  bool _error(int k) //输出错误提示，详见report
  {
    if(k == 0)
      return true;
    else if(k == 1)
      {
	cout << "Error Code " << k << ":Lack of Numbers." << endl;
	return false;
      }
    else if(k == 2)
      {
	cout << "Error Code " << k << ":Lack of Operators." << endl;
	return false;
      }
    else if(k == 3)
      {
	cout << "Error Code " << k << ":Blankets do not compare." << endl;
	return false;
      }
    else if(k == 4)
      {
	cout << "Error Code " << k << ":Excess decimal point." << endl;
	return false;
      }
    else if(k == 5)
      {
	cout << "Error Code " << k << ":Divided by 0." << endl;
	return false;
      }
    else if(k == 6)
      {
	cout << "Error Code " << k << ":Illegal characters exist." << endl;
	return false;
      }
    else if(k == 7)
      {
	cout << "Error Code " << k << ":Empty blanket exist." << endl;
	return false;
      }
    else
      {
	cout << "Error Code " << k << ":-Unknown-" << endl; //这一段没有什么用，单纯避免编译器提示没有返回值罢了
	return false;
      }
  }
  
  int _calculator() //把前面的函数归纳一下（正常使用的版本）
  {
    if(_error(exp_input(0)) == false)return 0;
    level();
    if(_error(post()) == false)return 0;
    if(_error(_calculate()) == false)
      return 0;
    else
      cout << _exp << " = " << cal[0] << endl;
    return 0;
  }
  
  int _calculator2() //用于展示算例的版本
  {
    if(_error(exp_input(1)) == false)return 0;
    level();
    if(_error(post()) == false)return 0;
    if(_error(_calculate()) == false)
      return 0;
    else
      cout << _exp << " = " << cal[0] << endl;
    return 0;
  }
};
#endif
